### 一 排查过程
使用的httpclient客户端,版本是:
在生产环境发现有时会报错:
怀疑是Nginx超时之后连接不可用,但是连接池里面没有剔除导致,为了简化排错,在本地直接设置了一个线程循环跑,把sleep时间调整成Nginx超时时间5s,代码如下:
这里把httpclient设置成了不重试的机制。在跑了之后,发现确实出现了NoHttpResponseException报错。
把当时的包抓下来,看到如下所示:
- 首先是三次建联过程;
- 中间两个get都成功,注意相差了5s,这是Nginx的keepalive时间;
- 下面是关键过程:
我们看到,
(1)在首个包发送完成之后5s,已经到达Nginx的keepalive时间,此时服务端主动断开连接,发送了FIN包(注意这里的客户端服务端是指的现在192是客户端(发起http请求的一方),服务端指的是176(Nginx))。
(2)客户端响应服务端请求,发送ACK包,此时192处于CLOSE_WAIT状态,176处于FIN_WAIT2状态,此时192仍然可以向176发送数据,但是176不会再向192发送数据,但是仍人可以接收192的数据;
(3)这时候我们发现,192向176发送了get请求,这个请求自然就被rst了;
### 二 httpclient使用
通常我们在使用的时候,不会考虑是否需要设置retry,实际上设置retry为false是非常重要的,在涉及到一致性的请求中,如果一次请求失败之后重新尝试,那中间会发生什么问题是未知的(代码返回失败!=请求失败)